using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using LFloatMath.Math;
using NetProtocol.POD;
using System.Collections.Generic;

namespace IQIGame.Onigao.Logic
{
    public class AIComponent : TComponent, IBehaviourSubject
    {
        public bool active;
        public Unit unit;
        private BattleAIController mAICtrl => this.unit.battle.playCtrl.AICtrl;
        private BattleAgent battleAgent => this.agent as BattleAgent;

        public void Initialize(bool defaultActive, string btPath)
        {
            this.active = defaultActive;
            if (string.IsNullOrEmpty(btPath))
            {
                // this.active = false;
                return;
            }

            this.mAICtrl.aiMgr.AddAgent<BattleAgent>(this, "Battle/" + btPath);
        }

        public BattleSkillPOD GetAIInput(ref List<LVector2Int> rPath)
        {
            var rSkillPriority = ListPool<int>.Get();
            this.mAIActive = true;
            if (this.battleAgent != null)
            {
                // 驱动一下行为树
                this.battleAgent.btexec();
                // 用行为树的结果计算AI
                var rPriorityDict = this.battleAgent.skillPriority;
                foreach (var rPair in rPriorityDict)
                {
                    rSkillPriority.Add(rPair.Key);
                }
                rSkillPriority.Sort((x, y) => -rPriorityDict[x].CompareTo(rPriorityDict[y]));
                this.battleAgent.Clear();
            }
            this.mAIActive = false;

            var rMoveStartPos = this.unit.pos;

            this.CheckAI(rMoveStartPos, rSkillPriority, out var nSkillID, out var nTargetGUID, out var rExecutePos, out var rPos, ref rPath);
            ListPool<int>.Put(rSkillPriority);
            var rTargetUnit = this.unit.battle.playCtrl.unitCtrl.GetUnit(nTargetGUID); // 没有目标就选自己
            var rTargetAspect = LVector2.zero;
            if (rTargetUnit != null)
            {
                rTargetAspect = rTargetUnit.pos - rPos;
            }
            var rPOD = new BattleSkillPOD()
            {
                skillId = nSkillID,
                unitId = this.unit.GUID,
                pos = rPos.ToPOD(),
                targetId = nTargetGUID,
                targetAspect = rTargetAspect.ToPOD(),
                targetPos = rExecutePos.ToPOD(),
            };

            return rPOD;
        }

        /// <summary>
        /// AI获取技能释放参数
        /// </summary>
        /// <param name="moveStartPos">移动起点</param>
        /// <param name="skillList">行为树指定的技能优先级列表</param>
        /// <param name="skillID">使用的技能</param>
        /// <param name="targetGUID">目标</param>
        /// <param name="moveTarget">移动目标</param>
        /// <param name="path">移动路径</param>
        private void CheckAI(LVector2 moveStartPos, List<int> skillList, out int skillID, out int targetGUID, out LVector2 executePos, out LVector2 moveTarget, ref List<LVector2Int> path)
        {
            var rAllActiveSkill = ListPool<Skill>.Get();
            var rTempPath = ListPool<LVector2Int>.Get();
            List<Unit> rAllUnits = ListPool<Unit>.Get();
            var rList = ListPool<Unit>.Get();
            var rSkillComp = this.unit.GetComponent<SkillComponent>(ETComponentType.SkillComponent);
            if (skillList.Count > 0)
            {
                // 这里的列表是按优先级排过序的
                for (int i = 0; i < skillList.Count; i++)
                {
                    if (rSkillComp.TryGetSkill(skillList[i], out var rSkill) && rSkill.activeSkill && rSkill.CanUsed())
                    {
                        rAllActiveSkill.Add(rSkill);
                    }
                }
            }
            else
            {
                for (int i = 0; i < rSkillComp.skills.Count; i++)
                {
                    var rSkill = rSkillComp.skills[i];
                    if (rSkill.activeSkill && rSkill.CanUsed())
                    {
                        rAllActiveSkill.Add(rSkill);
                    }
                }
                // 降序
                rAllActiveSkill.Sort((x, y) => -x.config.SkillSlotPriiority.CompareTo(y.config.SkillSlotPriiority));
            }
          
            var rMapCtrl = this.unit.battle.playCtrl.mapCtrl;
            skillID = default;
            targetGUID = default;
            moveTarget = this.unit.pos;
            executePos = this.unit.pos;

            var rAttr = this.unit.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent);
            var fMaxMove = rAttr.Get(EAttributeType.MoveRange) / LFloat.thousand;

            LFloat fNearestUnitDis = LFloat.zero;

            bool bSelected = false;
            for (int i = 0; i < rAllActiveSkill.Count; i++)
            {
                var rSkill = rAllActiveSkill[i];
                var rMainEffective = rSkill.mainPart.effectives[0];
                var rSelect = rMainEffective.select;
                rAllUnits.Clear();
                TargetSelectUtil.GetAllTargetsByRelation(this.unit, rSelect.targetRelation, ref rAllUnits);

                // 对目标排序
                this.SortUnit(rSkill.aiTargetSort, this.unit, ref rAllUnits);

                for (int j = 0; j < rAllUnits.Count; j++)
                {
                    var rUnit = rAllUnits[j];
                    if (rUnit.IsDead())
                    {
                        continue;
                    }
                    rTempPath.Clear();
                    // 有选择范围，把移动距离与选择范围加起来初步判断是否可以选中
                    if (rSelect.targetDisRange >= LFloat.zero)
                    {
                        var rMaxDis = fMaxMove + rSelect.targetDisRange;
                        var fUnitDis = (rUnit.pos - this.unit.pos).sqrMagnitude;
                        if (rMaxDis * rMaxDis < fUnitDis && fNearestUnitDis != LFloat.zero && fNearestUnitDis <= fUnitDis)
                        {
                            continue; // 超出距离 且  已经计算过走向此目标或更近目标的最远路径
                        }

                        // 需要移动
                        if (rSelect.targetDisRange * rSelect.targetDisRange < fUnitDis)
                        {
                            // 去往目标点
                            rMapCtrl.FindPath(moveStartPos, rUnit.pos, this.unit.radius, this.unit.GUID, ref rTempPath, fMaxMove, rSelect.targetDisRange);
                            if (rTempPath.Count <= 0)
                            {
                                rTempPath.Add(rMapCtrl.WorldToMapPos(moveStartPos));
                            }
                            executePos = rMapCtrl.MapToWorldPos(rTempPath[^1]);
                        }

                        // 记录找过的最近的点 不移动也可以
                        if (fNearestUnitDis == LFloat.zero || fNearestUnitDis > fUnitDis)
                        {
                            fNearestUnitDis = fUnitDis;
                        }
                    }

                    var rVirSelect = ClassPool.Get<SelectParam>();
                    rVirSelect.unit = rUnit;
                    rVirSelect.pos = rUnit.pos;
                    rVirSelect.aspect = rUnit.pos - executePos;
                    rList.Clear();
                    rSelect.TrySelect(rVirSelect, executePos, ref rList);

                    if (rList.Count > 0 || targetGUID == default)
                    {
                        targetGUID = rUnit.GUID;
                        executePos = rVirSelect.pos;
                        path.Clear();
                        path.AddRange(rTempPath);
                        if (rList.Count > 0)
                        {
                            skillID = rSkill.skillID;
                            bSelected = true;
                            break;
                        }
                    }
                }
                if (bSelected)
                {
                    break;
                }
            }

            if (path.Count > 0)
            {
                moveTarget = rMapCtrl.MapToWorldPos(path[^1]);
            }

            ListPool<Unit>.Put(rList);
            ListPool<Unit>.Put(rAllUnits);
            ListPool<LVector2Int>.Put(rTempPath);
            ListPool<Skill>.Put(rAllActiveSkill);
        }

        protected override void OnDispose()
        {
        }

        public override void OnCreate(TEntity entity)
        {
            this.unit = entity as Unit;
            // this.mAICtrl = this.self.battle.playCtrl.AICtrl;
        }

        private Dictionary<int, LFloat> sortFormulaCache = new Dictionary<int, LFloat>();

        private void SortUnit(IReadOnlyList<int> sortFormula, Unit self, ref List<Unit> rAllUnits)
        {
            if (sortFormula?.Count > 0)
            {
                rAllUnits.Sort((x, y) =>
                {
                    for (int i = 0; i < sortFormula.Count; i++)
                    {
                        var nFormulaID = sortFormula[i];
                        var fFormulaX = this.CalculateSortFormula(self, x, nFormulaID);
                        var fFormulaY = this.CalculateSortFormula(self, y, nFormulaID);
                        if (fFormulaX != fFormulaY)
                        {
                            return fFormulaX.CompareTo(fFormulaY);
                        }
                    }
                    return 0;
                });
            }
            else
            {
                // 没有就按距离排序
                rAllUnits.Sort((x, y) => (self.pos - x.pos).sqrMagnitude.CompareTo((self.pos - y.pos).sqrMagnitude));
            }
            this.sortFormulaCache.Clear();
        }

        private LFloat CalculateSortFormula(Unit self, Unit target, int nFormulaID)
        {
            var nKey = target.GUID << 8 | nFormulaID;
            if (this.sortFormulaCache.TryGetValue(nKey, out var fValue))
            {
                return fValue;
            }
            fValue = Formula.Calculate<LFloat>(nFormulaID, self, target);
            this.sortFormulaCache[nKey] = fValue;
            return fValue;
        }

        public IBehaviourAgent agent { get; set; }
        public bool isBehavTreeActive => this.mAIActive;
        private bool mAIActive;
    }
}